package com.gframework.mybatis.dao.mybatis.provider.per;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.ibatis.builder.annotation.ProviderContext;
import org.apache.ibatis.jdbc.SQL;
import org.apache.ibatis.reflection.MetaClass;

import com.gframework.mybatis.config.MybatisConfig;
import com.gframework.mybatis.dao.IViewDao;
import com.gframework.mybatis.dao.mybatis.provider.MybatisDaoInfo;
import com.gframework.mybatis.dao.mybatis.provider.PojoInfo;
import com.gframework.mybatis.dao.mybatis.provider.core.ProviderPlusLanguageDriver;
import com.gframework.sqlparam.MybatisParamNameCacheGenerator;
import com.gframework.sqlparam.Param;
import com.gframework.sqlparam.SqlParam;


/**
 * {@link IViewDao} 接口的sql提供类.<br>
 * 
 * @since 1.0.0
 * @author Ghwolf
 * 
 * @see IViewDao
 * @see ProviderPlusLanguageDriver
 */
public class ViewDaoProvider extends AbstractProvider{
	/**
	 * 查询列缓存
	 */
	private static final Map<String,String[]> selectColumnsCache = new ConcurrentHashMap<>();
	
	/**
	 * 查询全部数据.
	 * @see IViewDao#findAll()
	 */
	public static String findAll(ProviderContext context) {
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		return new SQL()
				.SELECT(pojo.getColumNames())
				.FROM(pojo.getTableName())
				.toString();
	}

	
	/**
	 * 根据自定义查询条件进行数据查询操作.
	 * @see IViewDao#find(SqlParam)
	 */
	public static String find(SqlParam param, ProviderContext context) {
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		SQL sql = new SQL()
				.SELECT(pojo.getColumNames())
				.FROM(pojo.getTableName());

		Map<String,Object> map = setSqlParam(param, sql);
		if (map != null && !map.isEmpty()) {
			ProviderPlusLanguageDriver.setParam(map);
		}
		if (param.getOrderBy() != null) {
			sql.ORDER_BY(param.getOrderBy());
		}
		return sql.toString();
	}

	/**
	 * 根据自定义查询条件，取得查询数据总数.
	 * @see IViewDao#count(SqlParam)
	 */
	public static String count(SqlParam param, ProviderContext context) {
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		SQL sql = new SQL()
				.SELECT("count(*)")
				.FROM(pojo.getTableName());

		Map<String,Object> map = setSqlParam(param, sql);
		if (map != null && !map.isEmpty()) {
			ProviderPlusLanguageDriver.setParam(map);
		}
		
		return sql.toString();
	}
	
	/**
	 * 根据一个查询条件，取得查询数据总数.
	 * @see IViewDao#countSingleCondition(Param)
	 */
	public static String countSingleCondition(Param param, ProviderContext context) {
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		SQL sql = new SQL()
				.SELECT("count(*)")
				.FROM(pojo.getTableName());
		if (param != null) {
			Map<String,Object> map = new HashMap<>();
			String w = param.getSql(map,new MybatisParamNameCacheGenerator());
			if (w != null) {
				sql.WHERE(w);
			}
			if (!map.isEmpty()) {
				ProviderPlusLanguageDriver.setParam(map);
			}
		}
		
		return sql.toString();
	}

	/**
	 * 根据指定的返回结果类型来构建select查询子句，并返回仅type中包含的字段.
	 * @see IViewDao#list(SqlParam, Class)
	 */
	public static String listByType(SqlParam param,Class<?> type,ProviderContext context) {
		SQL sql = getSQLByType(type,context);

		Map<String,Object> map = setSqlParam(param, sql);
		if (map != null && !map.isEmpty()) {
			ProviderPlusLanguageDriver.setParam(map);
		}
		if (param.getOrderBy() != null) {
			sql.ORDER_BY(param.getOrderBy());
		}
		return sql.toString();
	}
	
	/**
	 * 根据指定的一个条件和返回结果类型来构建select查询子句，并返回仅type中包含的字段.
	 * @see IViewDao#listByTypeCondition(Param, Class)
	 */
	public static String listByTypeCondition(Param param,Class<?> type,ProviderContext context) {
		SQL sql = getSQLByType(type,context);
		
		Map<String,Object> map = new HashMap<>();
		if (param != null) {
			String w = param.getSql(map, new MybatisParamNameCacheGenerator());
			if (w != null) {
				sql.WHERE(w);
			}
			if (!map.isEmpty()) {
				ProviderPlusLanguageDriver.setParam(map);
			}
		}
		return sql.toString();
	}
	
	private static SQL getSQLByType(Class<?> type,ProviderContext context) {
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		String[] selectColumns = selectColumnsCache.computeIfAbsent(pojo.getTableName() + " - " + type.getName(), t -> getTypeSelectColumns(type,pojo));
		
		return new SQL()
				.SELECT(selectColumns)
				.FROM(pojo.getTableName());
	}
	private static String[] getTypeSelectColumns(Class<?> type,PojoInfo pojo) {
		MetaClass mc = MybatisConfig.getMetaClass(type);
		String[] cs = pojo.getColumNames();
		String[] fs = pojo.getFieldNames();

		List<String> list = new ArrayList<>();
		for (int x = 0 ; x < cs.length ; x ++) {
			if (mc.hasSetter(fs[x])) {
				list.add(cs[x]);
			}
		}
		return list.toArray(new String[list.size()]);
	}

	/**
	 * 根据查询条件，取得某一个列的所有结果
	 */
	public static String listOneColumn(SqlParam param, String column, ProviderContext context) {
		MybatisDaoInfo mybatisDao = getMybatisDaoInfo(context);
		PojoInfo pojo = mybatisDao.getPojoInfo();
		
		SQL sql = new SQL().SELECT(column).FROM(pojo.getTableName());
		
		Map<String,Object> map = setSqlParam(param, sql);
		if (map != null && !map.isEmpty()) {
			ProviderPlusLanguageDriver.setParam(map);
		}
		if (param.getOrderBy() != null) {
			sql.ORDER_BY(param.getOrderBy());
		}
		return sql.toString();
	}

}

